VisualHMI - Modbus一主多从

本章节将介绍主从模式下(Modbus/FX2N/FX3U),读写PLC/驱动器的寄存器

以Modbus 为例,项目创建两个从站,第1个从站的站号为10,第2个从站的站号为20,如下所示:

image-20240103170621406

  1. Lua读PLC/驱动器的寄存器
  2. Lua写PLC/驱动器的寄存器
  3. Lua批量写寄存器

适用范围:VisualHMI - HMI&M系列

例程下载链接:ViusalHMI - 一主多从(点击下载)

1. Lua API说明

1.1. start_read(index,vtype, addr,quantity)

指定读取多个连续的变量,系统自动发指令读取变量地址

[!note|tip:注意] 1.只能用于主机模式,例如Modbus-Master、FX2N等

2.调用一次,屏幕会周期性发指令请求,停止需要调用stop_read

3.该函数没有返回值,需要配合get_xx获取寄存器的值

4.当前画面用到的变量地址或者有配置告警、资料采集,系统会自动读取,无需使用start_read。

5.若当前画面的控件绑定变量地址或者有配置告警、资料采集,脚本调用的start_read和前者有交叉部分,系统会优化读取指令,重新整合指令请求

  • index:索引,通常和停止读取搭配stop_read
  • vtype:数据类型
  • addr:开始读取的地址
  • quantity:读取的个数,最大120

1.2. stop_read(index)

停止读取多个连续的变量

[!note|tip:注意] 只能用于主机模式,例如Modbus-Master、FX2N等

  • index:索引,通常和开始读取搭配start_read

1.3. stop_all_read()

停止所有start_read开启的读取指令

[!note|tip:注意] 只能用于主机模式,例如Modbus-Master、FX2N等

1.4.set_auto_read(en)

使能画面控件绑定的寄存器自动读取

[!note|tip:注意] 1.只能用于主机模式,例如Modbus-Master、FX2N等

2.set_auto_read(0),禁止后,用start_read 控制读取

3.画面的控件绑定寄存器,默认自动读取

  • en:0-画面禁止自动读取,1-画面自动读取

1.5.select_slave(slave_id)

选择从站地址,用于多从机模式,如MODBUS、FX2N协议

  • slave_id:从机索引

2.后台读取

2.1.Lua 脚本

本文以Modbus为例,屏幕当主站。若需要后台一直轮询读取某些参数(任意界面下),可以在脚本调用start_read,只需要调用一次,将一直轮询读取,直到调用stop_read 或 stop_all_read()停止轮询,如下所示:


function on_init()

    select_slave(0)--选择第1个从站
    start_read(1,VT_4x, 0x0000, 3)--读取保持寄存器,从0x0000开始,连续3个寄存器
    start_read(2,VT_0x, 0x0000, 14)--读取线圈,从0x0000开始,连续14个寄存器
    redraw()

    select_slave(1)--选择第2个从站
    start_read(3,VT_4x, 0x0000, 3)--读取保持寄存器,从0x0000开始,连续3个寄存器
    start_read(4,VT_4x, 0x1000, 7)--读取保持寄存器,从0x1000开始,连续7个寄存器
    redraw()
end

若想全部通过脚本start_read 读取寄存器,则可以关闭画面控件绑定读取方式,在on_init() 调用 set_auto_read(0)

[!note|tip:注意] 若没有配置 set_auto_read(0)。轮询读取寄存器可以通过以下方式发出指令

1.脚本调用start_read

2.界面上的控件绑定从站寄存器地址

若这两种方式存在,系统会优化请求指令,合并交叉寄存器部分,减少重复的指令

function on_init()

    set_auto_read(0)--关闭控件读取

    select_slave(0)--选择第1个从站
    start_read(1,VT_4x, 0x0000, 3)--读取保持寄存器,从0x0000开始,连续3个寄存器
    start_read(2,VT_0x, 0x0000, 14)--读取线圈,从0x0000开始,连续14个寄存器
    redraw()

    select_slave(1)--选择第2个从站
    start_read(3,VT_4x, 0x0000, 3)--读取保持寄存器,从0x0000开始,连续3个寄存器
    start_read(4,VT_4x, 0x1000, 7)--读取保持寄存器,从0x1000开始,连续7个寄存器
    redraw()
end

2.2.运行预览

运行虚拟屏,屏幕发出的读取指令如下所以:

0A 01 00 00 00 10 3C BD -> start_read(2,VT_0x, 0x0000, 14)
0A 03 00 00 00 03 04 B0 -> start_read(1,VT_4x, 0x0000, 3)
14 03 00 00 00 03 07 0E -> start_read(3,VT_4x, 0x0000, 3)
14 03 10 00 00 07 02 0D -> start_read(4,VT_4x, 0x1000, 7)

Video_2024-01-15_142339

3.Lua 读寄存器

3.1.Lua 脚本

Lua脚本读取从机寄存器值,通常用于条件判断、计算和等。步骤如下所示

  1. 在脚本获取该寄存器时,确保后台有轮询请求,保证获取的值是最新的
  2. 获取寄存器前,要需要判断从机是否在线
  3. 获取寄存器前,需选择对应的从机
--读取保存寄存器
function mb_read_reg_03(slave, addr)

    local onlineState = get_uint16(VT_LW,0x01A3) -- 获取从机在线状态

    if ((onlineState >> slave) & 0x01) == 0x01 -- 读取从机在线状态
    then
        select_slave(slave)-- 选择从机
        return get_uint16(VT_4x, addr)--获取寄存器值
    else
        return false
    end
end

假设需要读取从机1/从机2的电量、电量,并计算总电压电量。如下所示

function on_run(screen)

    local Energy1 = mb_read_reg_03(0, 0x0000)
    local Energy2 = mb_read_reg_03(1, 0x0000)
    if Energy1 ~= false and Energy2 ~= false
    then
        set_uint16(VT_LW, 0x1000, Energy1 + Energy2)
    end

    local vol1 = mb_read_reg_03(0, 0x0001)
    local vol2 = mb_read_reg_03(1, 0x0001)
    if vol1 ~= false and vol2 ~= false
    then
        set_uint16(VT_LW, 0x1001, vol1 + vol2)
    end
end

3.2.运行预览

创建虚拟串口对,用Modbus slave和虚拟屏联机,如下所示,总电压、总电压实时变化:

Video_2024-01-15_151116~2

4.Lua 写寄存器

4.1.Lua 脚本

Lua脚本写从机寄存器值,通常在某个条件下或计算后,设置对应寄存器。步骤如下所示

  1. 获取寄存器前,要需要判断从机是否在线
  2. 获取寄存器前,需选择对应的从机
--设置保存寄存器
function mb_read_reg_03(slave, addr)

    local onlineState = get_uint16(VT_LW,0x01A3)

    if ((onlineState >> slave) & 0x01) == 0x01
    then
        select_slave(slave)
        return get_uint16(VT_4x, addr)
    else
        return false
    end
end

假设一个称重业务,一共有三种校准模式,如下所示

  • 零点校准:实重 = 57
  • 砝码校准:实重 = 砝码重量
  • 实物校准:实重=标定系数*砝码重量 // 保存码

function on_update(slave,vtype,addr)

    if vtype == VT_LW
    then
        if addr == 0x1004
        then
            local mode = get_uint16(VT_LW,  0x1003) -- 校准

            if mode == 0
            then
                mb_write_reg_06(0, 0x1002, 57)

            elseif mode == 1
            then
                --实重 = 砝码重量
                print('val == 1')
                local weightVal = get_uint16(VT_LW, 0x1005) -- 砝码重量
                mb_write_reg_06(0, 0x1002, weightVal)

            elseif mode == 2
            then
                --if (标定系数>0) && (保存码>0) 
                --then
                --    实重=标定系数*砝码重量 // 保存码
                --end
                local coeffi   = get_uint16(VT_LW, 0x1006) --标定系数
                local saveCode = get_uint16(VT_LW, 0x1007) --保存码

                if coeffi > 0 and saveCode > 0
                then
                    local weightVal = get_uint16(VT_LW, 0x1005) -- 砝码重量
                    mb_write_reg_06(0, 0x1002, (saveCode*weightVal)//coeffi )
                end
            end
        end
    end
end

4.2.运行预览

创建虚拟串口对,用Modbus slave和虚拟屏联机,如下所示,选择不同的校准方式和校准参数,校准结果实时变化:

Video_2024-01-15_153556

5.Lua 批量写线圈

5.1.Lua 脚本

VisualHMI批量写线圈最小单位是短整型,16个线圈对齐。本章节封装了批量写线圈的函数,直接调用以下接口

mb_write_coil_15(slave_id, addr, coilsTb)
  • slave_id:从站号索引
  • addr:起始地址
  • coilsTb:线圈值,字表

[!note|tip:注意] mb_write_coil_15 该函数为自行封装api,非系统api

假设一个业务逻辑,线圈起始地址为0x0000,设置连续14个线圈值,如下所示

coil c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13
val 1 0 1 0 0 0 1 0 1 1 1 1 0 0

按钮按下,执行批量设置寄存器逻辑,如下所示:


--批量写多个线圈
function mb_write_coil_15 (slave,addr,coils)

    if ((addr + #coils) > 0xFFFF ) or (#coils > 120) or (#coils <= 0)
    then
        return
    end

    local onlineState = get_uint16(VT_LW,0x01A3)
    if ((onlineState >> slave) & 0x01) == 0x01
    then
        feed_dog()
        select_slave(slave)
        local cnt = (#coils // 16) + (((#coils % 16) >= 0 ) and 1 or 0) -- 总共个数,16个线圈对齐
        local all = cnt*16
        local idx = (#(coils) + 1)

        if all > 120 --标准modbus 最大读写连续寄存器<=120
        then
            return
        end

        for i = idx, all --16bit对齐,获取实际对齐部分线圈的值
        do
            local ret = mb_read_coil_01(slave, ((addr + i) - 1))
            if ret == false
            then
                return false
            end
            coils[#coils + 1] = ret
       end

        local val = {}
        for i = 1, cnt --合并16位数据
        do
            val[i] = 0x0000
            for j = 0, 15
            do
                 val[i] = set_valbit(val[i], j, coils[(i - 1)*16 + j + 1])
            end
        end
        set_array(VT_0x, addr, val)

        return true
    else
        return false
    end

end

function on_update(slave,vtype,addr)
    if vtype == VT_LW
    then
        if addr == 0x1004
        then
            ......

        elseif addr == 0x2000
        then
            local val = get_uint16(VT_LW,  0x2000) -- 批量写
            if val == 1
            then
                --批量写入0x0000~0x000D, 14个寄存器  5B1A
                mb_write_coil_15(0, 0x0000, {1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0 })
            ....
            end
        end
    end
end

5.2.运行预览

创建虚拟串口对,用Modbus slave和虚拟屏联机,如下所示,点击批量写线圈按钮,0x0000~0x000D线圈对应变化

Video_2024-01-15_180412

6.Lua 批量写寄存器

6.1.Lua 脚本

VisualHMI批量写保持寄存器最小单位是16位数据。本章节封装了批量写寄存器的函数,直接调用以下接口

mb_write_reg_16(slave_id, addr, regsTb)

  • slave_id:从站号索引
  • addr:起始地址
  • regsTb:寄存器值,字表

[!note|tip:注意] mb_write_reg_16 该函数为自行封装api,非系统api

--批量写多个保存寄存器
function mb_write_reg_16 (slave,addr,regs)

    local onlineState = get_uint16(VT_LW,0x01A3)

    if ((onlineState >> slave) & 0x01) == 0x01
    then
        feed_dog()
        select_slave(slave)
        set_array(VT_4x, addr, regs)
        return true
    else
        return false
    end

end

function on_update(slave,vtype,addr)
    if vtype == VT_LW
    then
        if addr == 0x1004
        then
            ......

        elseif addr == 0x2000
        then
            local val = get_uint16(VT_LW,  0x2000) -- 批量写
            if val == 1
            then
                   ....
            elseif val == 2
            then
                --批量写入0x1000~0x1006, 7个寄存器
                mb_write_reg_16(1, 0x1000, {0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007})
            end
        end
    end
end

6.2.运行预览

创建虚拟串口对,用Modbus slave和虚拟屏联机,如下所示,点击批量写寄存器按钮,0x1000~0x1006寄存器对应变化

Video_2024-01-15_184327

Copyright ©Dacai all right reserved,powered by Gitbook该文件修订时间: 2024-01-16 08:38:30

results matching ""

    No results matching ""